package service

import (
	"context"
	"distributed/registry"
	"fmt"
	"log"
	"net/http"
)

// service.go 是一个通用的 service
// 它可以用来注册 service，也可以用来启动 service
// 它给用户一个选项，可以手动停止 service

// 这个项目将注册很多 Web 服务
// 将这些服务集中化管理
// 在一个地方集中启动这些服务

// Start 用于启动服务
func Start(ctx context.Context, host, port string,
	reg registry.Registration,
	registerHandlersFunc func()) (context.Context, error) {

	// 调用传进来的函数
	registerHandlersFunc()

	// 启动服务
	ctx = startService(ctx, reg.ServiceName, host, port)

	// 向 registry 发送 POST 请求，注册服务
	err := registry.RegisterService(reg)
	if err != nil {
		return ctx, err
	}

	return ctx, nil
}

// 启动服务器
func startService(ctx context.Context, serviceName registry.ServiceName,
	host, port string) context.Context {

	// 返回带有 Done Channel 的上下文对象
	// 只有当 cancel 方法被调用或 parent 的 Done Channel 被关闭时，它才会被关闭
	ctx, cancel := context.WithCancel(ctx)

	var srv http.Server
	srv.Addr = ":" + port

	go func() {
		// 启动服务
		// 如果启动过程中出现错误，那么这个错误将会被打印出来
		log.Println(srv.ListenAndServe())

		// 取消服务，需要传入自己的 url
		err := registry.ShutdownService(fmt.Sprintf("http://%s:%s", host, port))
		if err != nil {
			log.Println(err)
		}

		// 取消上下文
		cancel()
	}()

	go func() {
		// 输入任何键之后，关闭服务
		fmt.Printf("%v started. Press any key to stop. \n", serviceName)
		var s string
		fmt.Scanln(&s)

		// 取消服务
		err := registry.ShutdownService(fmt.Sprintf("http://%s:%s", host, port))
		if err != nil {
			log.Println(err)
		}

		// Shutdown 会比较优雅的关闭服务，不会打断任何正在使用的连接
		srv.Shutdown(ctx)
		cancel()
	}()

	return ctx
}
